--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit 18171377676a673c3e8af433124e36a03967dd9d
Parents : 9d50259
Author : Mark Qvist <mark@unsigned.io>
Date : 2025-10-17T22:44:30+02:00
Added LR1110 files
Changes
Diff
diff --git a/lr1110.cpp b/lr1110.cpp
new file mode 100755
index 0000000..f1288b4
--- /dev/null
+++ b/lr1110.cpp
@@ -0,0 +1,2589 @@
+// Copyright (c) Sandeep Mistry. All rights reserved.
+// Licensed under the MIT license.
+
+// Modifications and additions copyright 2023 by Mark Qvist
+// Obviously still under the MIT license.
+
+#include "Boards.h"
+
+#if MODEM == LR1110
+#include "lr1110.h"
+
+// todo, why is this in modem?
+#if MCU_VARIANT == MCU_ESP32
+// #if MCU_VARIANT == MCU_ESP32 and !defined(CONFIG_IDF_TARGET_ESP32S3)
+// #include "soc/rtc_wdt.h"
+// #endif
+
+// todo, why is this in modem?
+//https://github.com/espressif/esp-idf/issues/8855
+#include "hal/wdt_hal.h"
+
+ #define ISR_VECT IRAM_ATTR
+#else
+ #define ISR_VECT
+#endif
+
+int debug_print_enabled = 0;
+
+volatile uint8_t TXCompl_flag = 0;
+
+#define OP_RF_FREQ_6X 0x86
+#define OP_SLEEP_6X 0x84
+#define OP_STANDBY_6X 0x80
+#define OP_TX_6X 0x83
+#define OP_RX_6X 0x82
+#define OP_PA_CONFIG_6X 0x95
+#define OP_SET_IRQ_FLAGS_6X 0x08 // also provides info such as
+ // preamble detection, etc for
+ // knowing when it's safe to switch
+ // antenna modes
+#define OP_CLEAR_IRQ_STATUS_6X 0x02
+#define OP_GET_IRQ_STATUS_6X 0x12
+#define OP_RX_BUFFER_STATUS_6X 0x13
+#define OP_PACKET_STATUS_6X 0x14 // get snr & rssi of last packet
+#define OP_CURRENT_RSSI_6X 0x15
+#define OP_MODULATION_PARAMS_6X 0x8B // bw, sf, cr, etc.
+#define OP_PACKET_PARAMS_6X 0x8C // crc, preamble, payload length, etc.
+#define OP_STATUS_6X 0xC0
+#define OP_TX_PARAMS_6X 0x8E // set dbm, etc
+#define OP_PACKET_TYPE_6X 0x8A
+#define OP_BUFFER_BASE_ADDR_6X 0x8F
+#define OP_READ_REGISTER_6X 0x1D
+#define OP_WRITE_REGISTER_6X 0x0D
+#define OP_DIO3_TCXO_CTRL_6X 0x97
+#define OP_DIO2_RF_CTRL_6X 0x9D
+#define OP_CAD_PARAMS 0x88
+#define OP_CALIBRATE_6X 0x89
+#define OP_RX_TX_FALLBACK_MODE_6X 0x93
+#define OP_REGULATOR_MODE_6X 0x96
+#define OP_CALIBRATE_IMAGE_6X 0x98
+
+#define MASK_CALIBRATE_ALL 0x7f
+
+#define IRQ_TX_DONE_MASK_6X 0x01
+#define IRQ_RX_DONE_MASK_6X 0x02
+#define IRQ_HEADER_DET_MASK_6X 0x10
+#define IRQ_PREAMBLE_DET_MASK_6X 0x04
+#define IRQ_PAYLOAD_CRC_ERROR_MASK_6X 0x40
+#define IRQ_ALL_MASK_6X 0b0100001111111111
+
+#define MODE_LONG_RANGE_MODE_6X 0x01
+
+#define OP_FIFO_WRITE_6X 0x0E
+#define OP_FIFO_READ_6X 0x1E
+#define REG_OCP_6X 0x08E7
+#define REG_LNA_6X 0x08AC // no agc in sx1262
+#define REG_SYNC_WORD_MSB_6X 0x0740
+#define REG_SYNC_WORD_LSB_6X 0x0741
+#define REG_PAYLOAD_LENGTH_6X 0x0702 // https://github.com/beegee-tokyo/SX126x-Arduino/blob/master/src/radio/sx126x/sx126x.h#L98
+#define REG_RANDOM_GEN_6X 0x0819
+
+#define MODE_TCXO_3_3V_6X 0x07
+#define MODE_TCXO_3_0V_6X 0x06
+#define MODE_TCXO_2_7V_6X 0x06
+#define MODE_TCXO_2_4V_6X 0x06
+#define MODE_TCXO_2_2V_6X 0x03
+#define MODE_TCXO_1_8V_6X 0x02
+#define MODE_TCXO_1_7V_6X 0x01
+#define MODE_TCXO_1_6V_6X 0x00
+
+#define MODE_STDBY_RC_6X 0x00
+#define MODE_STDBY_XOSC_6X 0x01
+#define MODE_FALLBACK_STDBY_RC_6X 0x20
+#define MODE_IMPLICIT_HEADER 0x01
+#define MODE_EXPLICIT_HEADER 0x00
+
+#define SYNC_WORD_6X 0x1424
+
+#define XTAL_FREQ_6X (double)32000000
+#define FREQ_DIV_6X (double)pow(2.0, 25.0)
+#define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X)
+
+#if defined(NRF52840_XXAA)
+ extern SPIClass spiModem;
+ #define SPI spiModem
+#endif
+
+//extern SPIClass SPI;
+
+#define MAX_PKT_LENGTH 255
+
+lr11xx::lr11xx() :
+// _spiSettings(8E6, MSBFIRST, SPI_MODE0),
+ _spiSettings(8e8, MSBFIRST, SPI_MODE0),
+ _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _busy(LORA_DEFAULT_BUSY_PIN), _rxen(LORA_DEFAULT_RXEN_PIN),
+ _frequency(0),
+ _txp(0),
+ _sf(0x07),
+ _bw(0x04),
+ _cr(0x01),
+ _ldro(0x00),
+ _packetIndex(0),
+ _packetIndexRX(0),
+ _preambleLength(18),
+ _implicitHeaderMode(0),
+ _payloadLength(255),
+ _crcMode(1),
+ _fifo_tx_addr_ptr(0),
+ _fifo_rx_addr_ptr(0),
+ _packet{0},
+ _packetRX{0},
+ _preinit_done(false),
+ _onReceive(NULL)
+{
+ // overide Stream timeout value
+ setTimeout(0);
+ modulationDirty = packetParamsDirty = 1;
+}
+
+// debug - info
+uint8_t lOpState = 0;
+uint8_t readOpState = 0;
+// INT tracking
+int _db_pktLen;
+int _db_intcnt, _db_rxcnt;
+
+
+
+
+bool lr11xx::preInit() {
+
+ Serial.println("XXXXX");
+ Serial.println("PreInit");
+ Serial.println("XXXXX");
+
+#if 0
+ NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
+ NRF_CLOCK->TASKS_HFCLKSTART = 1;
+ while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
+ {
+ // wait for start
+ }
+#endif
+
+#if 1
+ NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
+ NRF_CLOCK->TASKS_LFCLKSTART = 1;
+ while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
+ {
+ // wait for start
+ }
+#endif
+
+ // generate byte of random with built in
+ // Random Number Gen (RNG)
+ NRF_RNG->EVENTS_VALRDY = 0;
+ NRF_RNG->TASKS_START = 1;
+ while (NRF_RNG->EVENTS_VALRDY == 0)
+ {
+ // wait for start
+ }
+ uint8_t rand1 = NRF_RNG->VALUE;
+ NRF_RNG->TASKS_STOP = 1;
+
+ Serial.print("lr1110 random ");
+ Serial.println(rand1);
+
+
+// SPI.begin();
+
+//---
+//void Wm1110Hardware::reset()
+// reset LR1110
+//---
+//ss high
+ pinMode(_ss, OUTPUT);
+ digitalWrite(_ss, HIGH);
+
+//nreset low 200us
+//nreset high 200us
+// delays 1ms here
+// hangs currently
+// reset();
+//busy should go low and radio in standby
+
+// waitOnBusy();
+
+///// --------------------------
+// PA setup
+
+// tx power setup
+// ral_lr11xx_bsp_get_tx_cfg -->
+// lr11xx_get_tx_cfg - radio_firmware_updater - platformio
+// HP and LP PA enabled below 2.4G
+//case LR11XX_WITH_LF_LP_HP_PA:
+
+// 2.4G is an option, when lower freq, then set:
+// pa_type = LR11XX_WITH_LF_LP_HP_PA; // = 2
+ //output_params->pa_ramp_time = LR11XX_RADIO_RAMP_48_US; // = 2
+
+
+
+
+
+
+///// --------------------------
+// tcxo
+// uint32_t startup_time_ms = smtc_modem_hal_get_radio_tcxo_startup_delay_ms( ); = return 30;
+// *xosc_cfg = RAL_XOSC_CFG_TCXO_RADIO_CTRL; // = 1
+// *supply_voltage = LR11XX_SYSTEM_TCXO_CTRL_1_8V; // = 2
+// // tick is 30.52µs
+// *startup_time_in_tick = lr11xx_radio_convert_time_in_ms_to_rtc_step( startup_time_ms );
+ // return ( uint32_t ) ( time_in_ms * LR11XX_RTC_FREQ_IN_HZ / 1000 );
+ // #define LR11XX_RTC_FREQ_IN_HZ 32768UL
+
+#if 0
+// tcxo notes
+lr11xx_status_t lr11xx_system_set_tcxo_mode( const void* context, const lr11xx_system_tcxo_supply_voltage_t tune,
+ const uint32_t timeout )
+{
+ const uint8_t cbuffer[LR11XX_SYSTEM_SET_TCXO_MODE_CMD_LENGTH] = { // 6
+ ( uint8_t ) ( LR11XX_SYSTEM_SET_TCXO_MODE_OC >> 8 ), // 279 = 0x0117
+ ( uint8_t ) ( LR11XX_SYSTEM_SET_TCXO_MODE_OC >> 0 ),
+ ( uint8_t ) tune,
+ ( uint8_t ) ( timeout >> 16 ),
+ ( uint8_t ) ( timeout >> 8 ),
+ ( uint8_t ) ( timeout >> 0 ),
+ };
+#endif
+///// --------------------------
+
+
+// pinMode(_ss, OUTPUT);
+// digitalWrite(_ss, HIGH);
+
+ Serial.println("==================");
+ Serial.println("------------------");
+ Serial.print("lr1110 _ss ");
+ Serial.println(_ss);
+
+
+
+#if 1
+ #if BOARD_MODEL == BOARD_RNODE_NG_22 || BOARD_MODEL == BOARD_HELTEC_LORA32_V3 || BOARD_MODEL == BOARD_HELTEC_CAPSULE_V3 || BOARD_MODEL == BOARD_HELTEC_CAPSULE_V3 || BOARD_MODEL == BOARD_HELTEC_WIRELESS_PAPER_1_1
+ SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
+ #else
+ SPI.begin();
+ #endif
+#endif
+
+
+// XXXXXXXXXXXXXXXXX -- move these out so we can do after reset
+#if 0
+
+// SetDioAsRfSwitch
+//C:\Users\cobra\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8\libraries\LBM_WM1110\src\internal\lbm_hal\ral_lr11xx_bsp.c
+// ral_lr11xx_bsp_get_rf_switch_cfg()
+//uint8_t RfSwEn = 0b1111; // enable DIO10 - DIO9 - DIO8 - DIO7 - DIO6 - DIO5
+uint8_t RfSwEn = 0b1111; // enable DIO10 - DIO8 - DIO7 - DIO6 - DIO5
+// standby none
+#if 0
+// initial match to firmware / Wio tracker dev board
+uint8_t rx_enable = 0b1; // switch 0
+uint8_t tx_enable = 0b11; // switch 0 and 1
+uint8_t tx_hp_enable = 0b10; // switch 1
+#else // T1000-E
+uint8_t rx_enable = 0b1001;
+uint8_t tx_enable = 0b1011;
+uint8_t tx_hp_enable = 0b1010;
+#endif
+#if 0
+uint8_t gnss_enable = 0b100; // switch 2
+uint8_t wifi_enable = 0b1000; // switch 3
+#else
+uint8_t gnss_enable = 0b0; // switch 2 - internal GNSS
+uint8_t wifi_enable = 0b0; // switch 3 - Wifi scanner
+#endif
+
+uint8_t cmd5[13] = {10,0,0x1,0x12,
+ RfSwEn,
+ 0, // none - standby
+
+// 0x9, 0xb, 0xa ? 1001, 1011, 1010
+
+ rx_enable,
+ tx_enable,
+ tx_hp_enable,
+ 0, // unused
+ gnss_enable,
+ wifi_enable
+ };
+
+cmdTransfer("dio sw cfg", cmd5);
+
+///// XXXXXXXX DISABLED
+
+#if defined(BOARD_WIO_TRACK_1110_DEV)
+// set tcxo mode
+// tune = 2, 1.8V - wio tracker dev
+// time 983 = 0x3d7
+//uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x3, 0xd7};
+// 1.6V, longer delay
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x3, 0xf2};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52)
+// 1.8V, shorter delay
+uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x0, 0xa4};
+#else // BOARD_SENSECAP_TRACKER_T1000E
+// tune = 0 , 1.6V tracker t1000-e
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x3, 0xd7};
+// longer delay
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x6, 0xd7};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52)
+uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+
+#endif
+
+cmdTransfer("tcxo", cmd4);
+
+
+
+//setpackettype
+uint8_t cmd[10] = {3,0,0x2,0xe,2};
+
+cmdTransfer("packettype lora", cmd);
+
+// geterrors
+uint8_t cmd3[10] = {2,3, 1,0xd};
+
+cmdTransfer("errors?", cmd3);
+
+
+// setmodulationparams
+
+//uint8_t cmd2[10] = {6,0, 0x02, 0x0f, 0x07 /*SF*/, 0x05 /*BW*/, 0x04 /*CR*/, 0 /*LDR*/};
+uint8_t cmd2[10] = {6,0, 0x02, 0x0f, _sf /*SF*/, _bw /*BW*/, _cr /*CR*/, _ldro /*LDR*/};
+cmdTransfer("modparams", cmd2);
+
+// geterrors
+//uint8_t cmd3[10] = {2,3, 1,0xd};
+
+cmdTransfer("errors", cmd3);
+
+
+// setpacketparams
+
+// setPAconfig
+
+// setTXParams
+
+
+// XXXXXXXXXXXXXXXXX -- move these out so we can do after reset
+#endif
+
+
+
+
+ _preinit_done = true;
+ return true;
+}
+
+
+void lr11xx::doSetup(void)
+{
+
+//Serial.println("Doing Setup - dio DCDC - TCXO >>>>>>>>>>>>");
+
+/// todo
+// early cal at freq before tcxo enable?
+//calibrate_image(906000000);
+// txco fails if this is done now
+
+
+#if defined(BOARD_WIO_TRACK_1110_DEV)
+// set tcxo mode
+// tune = 2, 1.8V - wio tracker dev
+// time 983 = 0x3d7
+////uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x3, 0xd7};
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x3, 0xd7};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52)
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52) - 1.8V
+uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x0, 0xa4};
+#else // BOARD_SENSECAP_TRACKER_T1000E
+// tune = 0 , 1.6V tracker t1000-e
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x3, 0xd7};
+// test with 0xa4 delay
+uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+// test with longer than 0xa4 delay, 1.8v
+//uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x3, 0xd7};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52)
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52) - 1.8V
+//uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x0, 0xa4};
+#endif
+
+cmdTransfer("tcxo", cmd4);
+
+
+#if 0
+// skip, has TCXO
+
+// Config LF clk
+// ConfigLfClock
+// external DIO11
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b10};
+// LF crystal, wait
+uint8_t cmd8[6] = {3,0,0x1,0x16, 0b101};
+// LF RC, no wait
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b0};
+cmdTransfer("ConfigLfClock", cmd8);
+#endif
+
+// SetRegMode
+// enable DC-DC for TX and when hi accuracy is needed
+//uint8_t cmd7[6] = {3,0,0x1,0x10, 1};
+// disable DC-DC - LDO only
+uint8_t cmd7[6] = {3,0,0x1,0x10, 0};
+cmdTransfer("setRegMode", cmd7);
+
+#if 0
+// SetLfClk
+// use ext 32k crystal, wait and rel busy
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b110};
+// RC osc, wait for 32k (defs)
+uint8_t cmd8[6] = {3,0,0x1,0x16, 0b0};
+cmdTransfer("LfClk", cmd8);
+#endif
+
+
+// SetDioAsRfSwitch
+//C:\Users\cobra\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8\libraries\LBM_WM1110\src\internal\lbm_hal\ral_lr11xx_bsp.c
+// ral_lr11xx_bsp_get_rf_switch_cfg()
+//uint8_t RfSwEn = 0b1111; // enable DIO10 - DIO9 - DIO8 - DIO7 - DIO6 - DIO5
+// enable upper bits?
+//uint8_t RfSwEn = 0b111111; // enable DIO10 - DIO9 - DIO8 - DIO7 - DIO6 - DIO5
+// Docs don't list 9, we don't use 10
+uint8_t RfSwEn = 0b01111; // enable DIO10 - DIO8 - DIO7 - DIO6 - DIO5
+// standby none
+
+// wio tracker dev
+#if defined(BOARD_WIO_TRACK_1110_DEV)
+uint8_t rx_enable = 0b1; // switch 0
+uint8_t tx_enable = 0b11; // switch 0 and 1
+uint8_t tx_hp_enable = 0b10; // switch 1
+#else // BOARD_SENSECAP_TRACKER_T1000E
+uint8_t rx_enable = 0b1001;
+uint8_t tx_enable = 0b1011;
+uint8_t tx_hp_enable = 0b1010;
+#endif
+#if 0
+uint8_t gnss_enable = 0b100; // switch 2
+uint8_t wifi_enable = 0b1000; // switch 3
+#else
+uint8_t gnss_enable = 0b0; // switch 2 - internal GNSS
+uint8_t wifi_enable = 0b0; // switch 3 - Wifi scanner
+#endif
+
+// setdioasrfswitch
+uint8_t cmd5[12] = {10,0,0x1,0x12,
+ RfSwEn,
+ 0, // none - standby
+ rx_enable,
+ tx_enable,
+ tx_hp_enable,
+ 0, // unused
+ gnss_enable,
+ wifi_enable,
+ };
+
+cmdTransfer("dio sw cfg", cmd5);
+
+#if 0
+//Move these up
+
+// Config LF clk
+// ConfigLfClock
+// external DIO11
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b10};
+// LF crystal, wait
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b101};
+// LF RC, no wait
+uint8_t cmd8[6] = {3,0,0x1,0x16, 0b0};
+cmdTransfer("ConfigLfClock", cmd8);
+
+
+// SetRegMode
+// enable DC-DC for TX and when hi accuracy is needed
+//uint8_t cmd7[6] = {3,0,0x1,0x10, 1};
+// no DC-DC converter enable.
+uint8_t cmd7[6] = {3,0,0x1,0x10, 0};
+cmdTransfer("setRegMode", cmd7);
+#endif
+
+// ConfigLfClock XXX not used with TCXO XXXX
+// use crystal, wait for ready
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b101};
+// user ext 32k crystal, wait and rel busy
+//uint8_t cmd8[6] = {3,0,0x1,0x16, 0b110};
+//cmdTransfer("LfClk", cmd8);
+
+#if 0
+#if defined(BOARD_WIO_TRACK_1110_DEV)
+// set tcxo mode
+// tune = 2, 1.8V - wio tracker dev
+// time 983 = 0x3d7
+////uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x3, 0xd7};
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x3, 0xd7};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52)
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52) - 1.8V
+uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x0, 0xa4};
+#else // BOARD_SENSECAP_TRACKER_T1000E
+// tune = 0 , 1.6V tracker t1000-e
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x3, 0xd7};
+// test with 0xa4 delay
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52)
+//uint8_t cmd4[10] = {6,0,0x1,0x17,0, 0, 0x0, 0xa4};
+// shorter 5000uS (RadioLib default) 0xa4 (5000 / 30.52) - 1.8V
+uint8_t cmd4[10] = {6,0,0x1,0x17,2, 0, 0x0, 0xa4};
+#endif
+
+cmdTransfer("tcxo", cmd4);
+#endif
+
+#if 0
+/// moved to before modulation params
+
+//setpackettype
+uint8_t cmd[10] = {3,0,0x2,0xe,2};
+
+cmdTransfer("packettype lora", cmd);
+
+// geterrors
+uint8_t cmd3[10] = {2,3, 1,0xd};
+
+cmdTransfer("errors?", cmd3);
+
+#endif
+
+// SyncWord / Private network (should be 0x12)
+//uint8_t cmd6[5] = {3,0, 0x2,0x8, 0x0};
+// public - should be 0x34
+//uint8_t cmd6[5] = {3,0, 0x2,0x8, 0x1};
+//cmdTransfer("PrvtNet", cmd6);
+// SetLoRaSyncWord
+//uint8_t cmd6[5] = {3,0, 0x2,0x2b, 0x14};
+uint8_t cmd6[5] = {3,0, 0x2,0x2b, 0x12};
+cmdTransfer("SyncWord", cmd6);
+
+//todo
+// not set in radiolib or meshtastic ??? try without
+// SetRssiCalibration
+// EVK defaults 600MHz - 2GHz
+uint8_t cmd9[16] = {13,0, 0x2,0x29, 0x22, 0x32, 0x43, 0x45, 0x64,
+ 0x55, 0x66, 0x76, 0x6, 0x0, 0x0 };
+cmdTransfer("SetRssiCal", cmd9);
+
+#if 0
+// setmodulationparams
+
+//uint8_t cmd2[10] = {6,0, 0x02, 0x0f, 0x07 /*SF*/, 0x05 /*BW*/, 0x04 /*CR*/, 0 /*LDR*/};
+uint8_t cmd2[10] = {6,0, 0x02, 0x0f, _sf /*SF*/, _bw /*BW*/, _cr /*CR*/, _ldro /*LDR*/};
+cmdTransfer("modparams", cmd2);
+#endif
+
+
+// geterrors
+//uint8_t cmd3[10] = {2,3, 1,0xd};
+
+//cmdTransfer("errors", cmd3);
+
+
+// setpacketparams
+
+// setPAconfig
+
+// setTXParams
+
+}
+
+
+// not valid - lr11xx
+uint8_t ISR_VECT lr11xx::readRegister(uint16_t address)
+{
+ return singleTransfer(OP_READ_REGISTER_6X, address, 0x00);
+}
+// not valid - lr11xx
+void lr11xx::writeRegister(uint16_t address, uint8_t value)
+{
+ singleTransfer(OP_WRITE_REGISTER_6X, address, value);
+}
+// not valid - lr11xx
+uint8_t ISR_VECT lr11xx::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value)
+{
+ waitOnBusy();
+
+ uint8_t response;
+
+ digitalWrite(_ss, LOW);
+
+ SPI.beginTransaction(_spiSettings);
+ SPI.transfer(opcode);
+ SPI.transfer((address & 0xFF00) >> 8);
+ SPI.transfer(address & 0x00FF);
+ if (opcode == OP_READ_REGISTER_6X) {
+ SPI.transfer(0x00);
+ }
+ response = SPI.transfer(value);
+ SPI.endTransaction();
+
+ digitalWrite(_ss, HIGH);
+
+ return response;
+}
+
+
+
+//int lr11xx::decode_stat(uint8_t stat, uint8_t print_it)
+int lr11xx::decode_stat(uint8_t stat)
+{
+ int doErr = 0;
+
+ Serial.print((stat & 1) ? " Int - " : " ___ - ");
+ switch ((stat>>1) & 7)
+ {
+ case 0:
+ Serial.println("CMD_FAIL");
+ doErr = 1;
+ break;
+ case 1:
+ Serial.println("CMD_PERR");
+ break;
+ case 2:
+ Serial.println("CMD_OK");
+ break;
+ case 3:
+ Serial.println("CMD_DAT");
+ break;
+ }
+// Serial.print(" - Int ");
+// Serial.println(stat & 1);
+
+#if 0
+ if(doErr) {
+ Serial.println("get errors");
+
+ uint8_t cmd2[8] = {5,0, 0x01, 0x0d, 0x0, 0x0,0x0};
+ cmdTransfer("modparams", cmd2);
+ Serial.print("Fail errors ");
+ Serial.print(cmd2[5] & 0x1);
+ Serial.println(cmd2[6]);
+
+ }
+#endif
+ return doErr;
+}
+
+int lr11xx::decode_stat(const char *prt,uint8_t stat1,uint8_t stat2,uint8_t print_it)
+{
+ int doErr = 0;
+
+ //if (!print_it) return 0;
+
+
+// Serial.print((stat & 1) ? " Int - " : " ___ - ");
+ switch ((stat1>>1) & 7)
+ {
+ case 0:
+ Serial.print(prt);
+ Serial.println(" ---- > CMD_FAIL");
+ doErr = 1;
+ break;
+ case 1:
+ Serial.println(" ---- > CMD_PERR");
+ break;
+ case 2:
+ if(print_it) Serial.println("CMD_OK");
+ break;
+ case 3:
+ if(print_it) Serial.println(" ---- > CMD_DAT");
+ break;
+ }
+
+ return doErr;
+
+}
+
+
+int lr11xx::decode_stat(uint8_t stat, uint8_t stat2)
+{
+ //int cmd_fail = decode_stat(stat, 1);
+ int cmd_fail = decode_stat(stat);
+ switch ((stat2 & 0xf0)>>4)
+ {
+ case 0:
+ Serial.print("RST CLR");
+ break;
+ case 1:
+ Serial.print("RST A-Anlg");
+ break;
+ case 2:
+ Serial.print("RST A-Rpin");
+ break;
+ case 3:
+ Serial.print("RST A-Sys");
+ break;
+ case 4:
+ Serial.print("RST A-WDog");
+ break;
+ case 5:
+ Serial.print("RST A-IOCD rstrt");
+ break;
+ case 6:
+ Serial.print("RST A-RTC");
+ break;
+ default:
+ Serial.print("RST ACT");
+ break;
+ }
+ switch ((stat2>>1) & 7)
+ {
+ case 0:
+ Serial.print(" Sleep");
+ break;
+ case 1:
+ Serial.print(" STD RC");
+ break;
+ case 2:
+ Serial.print(" STD Xtc");
+ break;
+ case 3:
+ Serial.print(" FS");
+ break;
+ case 4:
+ Serial.print(" RX");
+ break;
+ case 5:
+ Serial.print(" TX");
+ break;
+ case 6:
+ Serial.print(" RDO");
+ break;
+ }
+ switch (stat2 & 1)
+ {
+ case 0:
+ Serial.println(" bload");
+ break;
+ case 1:
+ Serial.println(" flash");
+ break;
+ }
+ return cmd_fail;
+}
+
+
+uint16_t ISR_VECT lr11xx::cmdTransfer(const char *prt, uint8_t *cmd)
+{
+ return cmdTransfer(prt, cmd, 0);
+}
+
+
+uint16_t ISR_VECT lr11xx::cmdTransfer(const char *prt, uint8_t *cmd, bool print_it)
+{
+ uint8_t cnt = cmd[0];
+ uint8_t cnt_in = cmd[1];
+ uint8_t response;
+ uint8_t stat1,stat2;
+ uint8_t cmd_fail;
+
+ //print_it=0;
+
+ if(print_it) {
+ Serial.print("go cmd -");
+ Serial.println(prt);
+ }
+
+ waitOnBusy(0);
+ SPI.beginTransaction(_spiSettings);
+ digitalWrite(_ss, LOW);
+
+ for (int x=0; x<cnt; x++)
+ {
+ response = SPI.transfer(cmd[2+x]);
+ if (print_it) Serial.println(response);
+ cmd[2+x] = response;
+ if(!x)
+ stat1=response;
+ // decode stat1, stat2
+ if(x==1)
+ if (print_it) cmd_fail = decode_stat(stat1,response);
+ }
+ if(debug_print_enabled) {
+ Serial.print(prt);
+ Serial.print("- ");
+ decode_stat(prt,stat1,response,1);
+ }
+ decode_stat(prt,stat1,response,print_it);
+
+ // command out complete
+ digitalWrite(_ss, HIGH);
+
+ // if response, wait for busy low, then drop _cs again
+ if(cnt_in>0) {
+ waitOnBusy(0);
+ digitalWrite(_ss, LOW);
+
+ for (int x=0; x<cnt_in; x++)
+ {
+ response = SPI.transfer(0);
+ if (print_it) {Serial.print(response); Serial.print(" "); }
+ cmd[2+cnt+x] = response;
+ }
+ digitalWrite(_ss, HIGH);
+ }
+
+ SPI.endTransaction();
+ if (print_it) Serial.println(" done\n----");
+
+ readOpState = (cmd[3]>>1) & 7;
+
+// Debug - states
+#if 0
+ switch ((cmd[3]>>1) & 7)
+ {
+ case 0:
+ //Serial.print(" Sleep");
+ break;
+ case 1:
+ //Serial.print(" STD RC");
+ break;
+ case 2:
+ //Serial.print(" STD Xtc");
+ break;
+ case 3:
+ //Serial.print(" FS");
+ break;
+ case 4:
+ //Serial.print(" RX");
+ break;
+ case 5:
+ //Serial.print(" TX");
+ break;
+ case 6:
+ //Serial.print(" RDO");
+ break;
+ }
+#endif
+
+ return 0;
+}
+
+uint16_t ISR_VECT lr11xx::A32Transfer(uint16_t opcode, uint16_t address, uint16_t value)
+{
+ waitOnBusy();
+
+ uint8_t response;
+ uint16_t response_msb;
+ uint16_t response_lsb;
+
+ digitalWrite(_ss, LOW);
+
+ Serial.println("go");
+ SPI.beginTransaction(_spiSettings);
+ Serial.println(SPI.transfer((opcode & 0xFF00) >> 8));
+ Serial.println(SPI.transfer(opcode & 0x00FF));
+ //SPI.transfer((address & 0xFF00) >> 8);
+ //SPI.transfer(address & 0x00FF);
+ //if (opcode == OP_READ_REGISTER_6X) {
+ // SPI.transfer(0x00);
+ //}
+ ////SPI.transfer((value & 0xFF00) >> 8);
+ //SPI.transfer(value & 0x00FF);
+ //response_msb = SPI.transfer(value);
+ //response_lsb = SPI.transfer(value);
+ response = SPI.transfer(0);
+ Serial.println(response);
+ if (response & 0x4) {
+ Serial.println(SPI.transfer(0));
+ Serial.println(SPI.transfer(0));
+ Serial.println(SPI.transfer(0));
+ Serial.println(SPI.transfer(0));
+ }
+ SPI.endTransaction();
+ Serial.println("end");
+
+ digitalWrite(_ss, HIGH);
+
+ return (response_msb << 8) | response_lsb;
+}
+
+void lr11xx::rxAntEnable()
+{
+ if (_rxen != -1) {
+ digitalWrite(_rxen, HIGH);
+ }
+}
+
+void lr11xx::loraMode() {
+
+ //setpackettype
+ uint8_t cmd[10] = {3,0,0x2,0xe,2};
+
+//dododo
+ cmdTransfer("packettype lora", cmd);
+
+#if 0
+ Serial.print("loramode st ");
+ Serial.print(cmd[2]);
+ Serial.print(" ");
+ Serial.print(cmd[3]);
+ Serial.print(" ");
+ Serial.println(cmd[4]);
+#endif
+
+ // test mode
+ //uint8_t buf2[10] = {2,2, 0x02, 0x02 };
+
+ //cmdTransfer("packettype", buf2);
+ //Serial.print("LM stat1 ");
+ //decode_stat(buf2[2], buf2[3]);
+#if 0
+ Serial.print(buf2[2]);
+ Serial.print(" stat2 ");
+ Serial.print(buf2[3]);
+ Serial.print(" stat rt ");
+ Serial.print(buf2[4]);
+ Serial.print(" lora2? ");
+ Serial.println(buf2[5]);
+#endif
+
+ //getErrors2();
+
+
+ #if 0
+ // enable lora mode on the SX1262 chip
+ uint8_t mode = MODE_LONG_RANGE_MODE_6X;
+ executeOpcode(OP_PACKET_TYPE_6X, &mode, 1);
+ #endif
+}
+
+void lr11xx::waitOnBusy(uint8_t doYield) {
+ unsigned long time = millis();
+ unsigned long time2 = time;
+ long count = 0;
+ if (_busy != -1) {
+ while (digitalRead(_busy) == HIGH)
+ {
+ count++;
+ time2 = millis();
+ if (millis() >= (time + 300)) {
+ Serial.println("waitonbusy timeout!!");
+ break;
+ }
+ // do nothing
+ if(doYield) yield();
+ }
+ //Serial.print("busy was = ");
+ //Serial.println(time2 - time);
+ //Serial.println(count);
+ }
+}
+
+void lr11xx::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
+{
+ waitOnBusy();
+
+ digitalWrite(_ss, LOW);
+
+ SPI.beginTransaction(_spiSettings);
+ SPI.transfer(opcode);
+
+ for (int i = 0; i < size; i++)
+ {
+ SPI.transfer(buffer[i]);
+ }
+
+ SPI.endTransaction();
+
+ digitalWrite(_ss, HIGH);
+}
+
+void lr11xx::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
+{
+ waitOnBusy();
+
+ digitalWrite(_ss, LOW);
+
+ SPI.beginTransaction(_spiSettings);
+ SPI.transfer(opcode);
+ SPI.transfer(0x00);
+
+ for (int i = 0; i < size; i++)
+ {
+ buffer[i] = SPI.transfer(0x00);
+ }
+
+ SPI.endTransaction();
+
+ digitalWrite(_ss, HIGH);
+}
+
+// lr1110
+void lr11xx::writeBuffer(const uint8_t* buffer, size_t size)
+{
+
+ uint8_t cmd[4] = {2,0,0x1, 0x9 };
+ uint8_t response, stat1;
+
+
+ waitOnBusy(0);
+ digitalWrite(_ss, LOW);
+ SPI.beginTransaction(_spiSettings);
+
+ for (int x=0; x<2; x++)
+ {
+ response = SPI.transfer(cmd[2+x]);
+ if(!x)
+ stat1 = response;
+ }
+ // write data (TX)
+ for (int x=0; x<size; x++)
+ {
+ response = SPI.transfer(buffer[x]);
+ if(x<6 || x>size-3) {
+ }
+ }
+
+ SPI.endTransaction();
+ digitalWrite(_ss, HIGH);
+}
+
+// lr1110
+void lr11xx::readBuffer(uint8_t* buffer, size_t size)
+{
+ uint8_t cmd[7] = {4,0,0x1, 0xa, _fifo_rx_addr_ptr, size};
+ uint8_t cnt = cmd[0];
+ uint8_t response, stat1, stat2, stat3;
+
+ waitOnBusy(0);
+ digitalWrite(_ss, LOW);
+ SPI.beginTransaction(_spiSettings);
+
+ for (int x=0; x<cnt; x++)
+ {
+ response = SPI.transfer(cmd[2+x]);
+ }
+ digitalWrite(_ss, HIGH);
+ SPI.endTransaction();
+
+ waitOnBusy();
+ digitalWrite(_ss, LOW);
+ SPI.beginTransaction(_spiSettings);
+
+ response = SPI.transfer(0);
+ for (int x=0; x<size; x++)
+ {
+ response = SPI.transfer(0);
+ buffer[x] = response;
+ }
+ SPI.endTransaction();
+ digitalWrite(_ss, HIGH);
+ _local_rx_buffer = size;
+
+}
+
+// lr1110
+void lr11xx::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
+
+if(modulationDirty==0) return;
+modulationDirty = 0;
+
+#if 0
+ uint8_t buf[8];
+
+
+ buf[0] = sf;
+ buf[1] = bw;
+ buf[2] = cr;
+ // low data rate toggle
+ buf[3] = ldro;
+ // unused params in LoRa mode
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+ buf[6] = 0x00;
+ buf[7] = 0x00;
+#endif
+
+ uint8_t cmd2[10] = {6,0, 0x02, 0x0f, sf /*SF*/, bw /*BW*/, cr /*CR*/, ldro /*LDR*/};
+ #if 0
+ Serial.print("sf ");
+ Serial.print(cmd2[4]);
+ Serial.print(" bw ");
+ Serial.print(cmd2[5]);
+ Serial.print(" cr ");
+ Serial.print(cmd2[6]);
+ Serial.print(" ldro ");
+ Serial.println(cmd2[7]);
+ #endif
+
+ cmdTransfer("modparams", cmd2);
+}
+
+void lr11xx::getErrors(void)
+{
+ // geterrors
+ uint8_t cmd3[10] = {2,3, 1,0xd};
+ cmdTransfer("err cmd", cmd3);
+
+ uint8_t cmd2[5] = {2,0, 1,0xe};
+ cmdTransfer("err clr", cmd2);
+
+}
+
+// lr1110 done
+void lr11xx::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
+
+ if(packetParamsDirty==0) return;
+ packetParamsDirty=0;
+
+ // packet params
+ uint8_t buf[10] = {8,0, 0x02, 0x10 };
+
+ buf[4] = uint8_t((preamble & 0xFF00) >> 8);
+ buf[5] = uint8_t((preamble & 0x00FF));
+ buf[6] = headermode;
+ buf[7] = length;
+ buf[8] = crc;
+ // standard IQ setting (no inversion)
+ buf[9] = 0x00;
+
+#if 0
+ Serial.print("Packet params - preamble ");
+ Serial.print(preamble);
+ Serial.print(" headermode ");
+ Serial.print(headermode);
+ Serial.print(" len ");
+ Serial.print(length);
+ Serial.print(" crc ");
+ Serial.println(crc);
+#endif
+
+ cmdTransfer("packet params", buf);
+}
+
+void lr11xx::reset(void) {
+
+ if (_reset != -1) {
+ pinMode(_reset, OUTPUT);
+
+ // perform reset
+ digitalWrite(_reset, LOW);
+ delay(2);
+ digitalWrite(_reset, HIGH);
+ delay(2);
+
+ waitOnBusy(0);
+
+#if 0
+ // Reboot / Restart
+ uint8_t cmd3[9] = {3,0,0x1,0x18,0x0};
+
+ cmdTransfer("->getStat reboot", cmd3, 1);
+#endif
+
+ /// Clear reset status
+ // GetStatus, last 4 are irq status on return
+ uint8_t cmd[9] = {6,0,0x1,0x0, 0x0,0x0,0x0,0x0};
+
+ cmdTransfer("->getStat clr rst", cmd, 1);
+
+ uint8_t cmd2[9] = {6,0,0x1,0x0, 0x0,0x0,0x0,0x0};
+
+ cmdTransfer("->getStat reset2", cmd2, 1);
+
+ }
+
+ // setup pins
+ // Not needed for current firmware,
+ // but supports T1000-E sensor power
+ #if defined(BOARD_SENSECAP_TRACKER_T1000E)
+ //pinMode(pin_3v3_en_sensor, OUTPUT);
+ //digitalWrite(pin_3v3_en_sensor, HIGH);
+ #endif
+
+}
+
+// lr1110
+void lr11xx::calibrate(uint8_t cal) {
+
+ // all
+ //uint8_t buf[7] = {3,0, 0x01, 0xf, 0b111111 };
+ //uint8_t buf[7] = {3,0, 0x01, 0xf, 0b1010 };
+
+ //uint8_t buf[7] = {3,0, 0x01, 0xf, 0b100111 };
+ //uint8_t buf[7] = {3,0, 0x01, 0xf, 0xff };
+ uint8_t buf[7] = {3,0, 0x01, 0xf, cal };
+
+ cmdTransfer("calib", buf);
+
+}
+
+// lr1110
+void lr11xx::calibrate_image(long frequency) {
+ uint8_t image_freq[2] = {0};
+ uint8_t freq_error = 0;
+
+
+ // lr1110
+ if (frequency >= 430E6 && frequency <= 440E6) {
+ image_freq[0] = 0x6B;
+ image_freq[1] = 0x6E;
+ }
+ else if (frequency >= 470E6 && frequency <= 510E6) {
+ image_freq[0] = 0x75;
+ image_freq[1] = 0x81;
+ }
+ else if (frequency >= 779E6 && frequency <= 787E6) {
+ image_freq[0] = 0xC1;
+ image_freq[1] = 0xC5;
+ }
+ else if (frequency >= 863E6 && frequency <= 870E6) {
+ image_freq[0] = 0xD7;
+ image_freq[1] = 0xDB;
+ }
+ else if (frequency >= 902E6 && frequency <= 928E6) {
+ image_freq[0] = 0xE1;
+ image_freq[1] = 0xE9;
+ } else {
+ freq_error = 1;
+ }
+
+ if(!freq_error) {
+ uint8_t buf[7] = {4,0, 0x01, 0x11, image_freq[0], image_freq[1] };
+
+ cmdTransfer("calib img", buf);
+
+ Serial.print("calib img - freq ");
+ Serial.print(frequency);
+ Serial.print(" ");
+ Serial.print(image_freq[0]);
+ Serial.print(" ");
+ Serial.println(image_freq[1]);
+ } else {
+ Serial.println("calib img - FREQ ERROR EEEEE");
+
+ }
+}
+
+void lr11xx::getErrors2(void)
+{
+
+ Serial.println("get errors2");
+ uint8_t cmd2[8] = {5,0, 0x01, 0x0d, 0x0, 0x0,0x0};
+ cmdTransfer("getErr", cmd2);
+ Serial.print("Fail errors ");
+ Serial.print(cmd2[5]);
+ Serial.print(" (");
+ Serial.print(cmd2[5] & 0x1);
+ Serial.print("), ");
+ Serial.println(cmd2[6]);
+
+}
+
+
+
+int lr11xx::begin(long frequency)
+{
+
+Serial.println("\n Lora begin lr1110\n - - RESET - - XXXXXXXXXXXXXXXXXXXXXXX");
+
+ if (_busy != -1) {
+ pinMode(_busy, INPUT);
+ }
+
+ reset();
+
+#if 0
+ if (_busy != -1) {
+ pinMode(_busy, INPUT);
+ }
+#endif
+
+/// reset clears chip, redo preInit?
+// No, resets bluetooth?
+#if 0
+ if (!preInit()) {
+ return false;
+ }
+#else
+ if (!_preinit_done) {
+ Serial.println("lr1110 preinit ");
+ if (!preInit()) {
+ return false;
+ }
+ }
+#endif
+
+ if (_rxen != -1) {
+ pinMode(_rxen, OUTPUT);
+ }
+
+ //calibrate(0b1101);
+ //calibrate(0b111111);
+
+ doSetup();
+
+ //Serial.println("lr1110 en tcxo ");
+ //enableTCXO();
+
+ // todo
+ //loraMode();
+ //standby();
+
+// todo
+ // Set sync word
+ //setSyncWord(SYNC_WORD_6X);
+
+// No for LR1110?
+// #if DIO2_AS_RF_SWITCH
+// // enable dio2 rf switch
+// uint8_t byte = 0x01;
+// executeOpcode(OP_DIO2_RF_CTRL_6X, &byte, 1);
+// #endif
+
+ Serial.print(" .rxAnt. ");
+ rxAntEnable();
+
+ Serial.print(" .freq. ");
+ setFrequency(frequency);
+
+ getErrors2();
+
+ /// todo - startup calibrates at 915MHz
+ /// if freq is changed, need to CalibImage
+ /// if temp change, need to calibrate
+/// Serial.println("lr1110 calibrate img");
+/// calibrate_image(frequency);
+ Serial.println("lr1110 calibrate");
+ //calibrate(0b100010);
+ calibrate(0b111111);
+
+// todo - testing after calibrate
+ calibrate_image(frequency);
+
+ getErrors2();
+
+ //setTxPower(2);
+ ////setTxPower(6);
+
+ Serial.print(" .CRC. ");
+ enableCrc();
+
+ // todo
+ // set LNA boost
+ //writeRegister(REG_LNA_6X, 0x96);
+
+ // todo
+ // set base addresses
+ //uint8_t basebuf[2] = {0};
+ //executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2);
+
+ //setpackettype
+ uint8_t cmd[10] = {3,0,0x2,0xe,2};
+
+ cmdTransfer("packettype lora", cmd);
+
+
+ setModulationParams(_sf, _bw, _cr, _ldro);
+ setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+
+Serial.println(".... done ");
+
+ return 1;
+}
+
+void lr11xx::end()
+{
+ // put in sleep mode
+ sleep();
+
+ // stop SPI
+ SPI.end();
+
+ _preinit_done = false;
+}
+
+// lr1110
+// for TX
+int lr11xx::beginPacket(int implicitHeader)
+{
+ standby();
+
+ loraMode();
+
+ if (implicitHeader) {
+ implicitHeaderMode();
+ } else {
+ explicitHeaderMode();
+ }
+
+ _payloadLength = 0;
+ _packetIndex = 0;
+ packetParamsDirty=1;
+ _fifo_tx_addr_ptr = 0;
+ // set in endPacket()
+ //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+
+ modulationDirty=1;
+ setModulationParams(_sf, _bw, _cr, _ldro);
+ // length not known yet...
+ //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+
+ return 1;
+}
+
+uint8_t _wait_tx_cmpl;
+
+// lr1110
+// for TX
+int lr11xx::endPacket()
+{
+
+ _payloadLength = _packetIndex;
+ packetParamsDirty=1;
+
+// both in beginPacket
+// setModulationParams(_sf, _bw, _cr, _ldro);
+ setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+
+ writeBuffer(_packet, _payloadLength);
+
+ // put in single TX mode
+ // SetTX
+ uint8_t cmd2[8] = {5,0,0x2,0xa,0x0,0x0,0x0};
+ TXCompl_flag=0;
+
+ cmdTransfer("->tx", cmd2);
+ _wait_tx_cmpl = 1;
+
+
+ // Rely on INT call setting this (wait)
+ while (!TXCompl_flag) {
+ yield();
+ }
+ _db_intcnt--;
+ checkTXstat();
+ TXCompl_flag=0;
+
+ return 1;
+}
+
+
+
+void lr11xx::checkTXstat()
+{
+ uint8_t dat[3], done=0;
+ //dodo
+ while(!done) {
+ dioStat(0,&(dat[0]),&(dat[1]),&(dat[2]));
+ if(dat[2] & 0b100) {
+ // found TXDone
+ done=1;
+ uint8_t clr[9] = {6,0,0x1,0x14,0x0,0x0,0x0,0b100};
+ cmdTransfer("->clear irqs", clr, 0);
+ }
+ yield();
+
+ }
+}
+
+
+// lr1110
+// RNode main firmware expects the following status bits
+ // Status flags
+// const uint8_t SIG_DETECT = 0x01;
+// const uint8_t SIG_SYNCED = 0x02;
+// const uint8_t RX_ONGOING = 0x04;
+uint8_t lr11xx::modemStatus() {
+
+ uint8_t byte = 0x00;
+#if 0 //debug rx
+ // GetStatus, last 4 are irq status on return
+ uint8_t cmd[9] = {6,0,0x1,0x0, 0x0,0x0,0x0,0x0};
+ uint8_t toClr = 0x00;
+ int debug = 0;
+
+ cmdTransfer("->Modem-IrqStat", cmd, 0);
+ // Preamble detected
+ if(cmd[7] & 0b10000) {
+ byte = byte | 0x01 | 0x04;
+ toClr = 0b10000;
+ Serial.print("Prembl ");
+ // debug rx
+ debug=1;
+ }
+ // Header Valid
+ if(cmd[7] & 0b100000) {
+ byte = byte | 0x02 | 0x04;
+ toClr |= 0b100000;
+ Serial.print("HdrVl ");
+ debug=1;
+ }
+
+ // clear active IRQs
+ //uint8_t cmd2[9] = {6,0,0x1,0x14, 0x0,0x0,0x0,0b110000};
+ if(toClr) {
+ uint8_t cmd2[9] = {6,0,0x1,0x14, 0x0,0x0,0x0,toClr};
+ cmdTransfer("->Clr Act IRQs", cmd2);
+ Serial.print("Clr ");
+ debug=1;
+ } else {
+ //Serial.println("Clr Irq -NA");
+ }
+
+ if(debug)
+ Serial.println(".");
+
+ #if 0
+ if(cmd[7]) {
+ Serial.print("modemstat cmd-7 ");
+ Serial.println(cmd[7]);
+ }
+ if(byte>0) {
+ Serial.print("modemstat ");
+ Serial.println(byte);
+ }
+ #endif
+
+#endif
+ return byte;
+
+#if 0
+ Serial.println("XXXX\n XXXXX modemStatus\n -----------------------");
+ // imitate the register status from the sx1276 / 78
+ uint8_t buf[2] = {0};
+
+ executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
+ uint8_t clearbuf[2] = {0};
+ uint8_t byte = 0x00;
+
+ if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) {
+ byte = byte | 0x01 | 0x04;
+ // clear register after reading
+ clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X;
+ }
+
+ if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) {
+ byte = byte | 0x02 | 0x04;
+ }
+
+ executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
+
+ return byte;
+#endif
+}
+
+unsigned long preamble_detected_at = 0;
+extern long lora_preamble_time_ms;
+extern long lora_header_time_ms;
+bool false_preamble_detected = false;
+
+bool lr11xx::dcd() {
+ uint8_t clr[9] = {6,0,0x1,0x14,0, 0, 0, 0};
+ uint8_t stat1 = 0;
+ dioStat(0,0,0, &stat1);
+
+ //uint8_t buf[2] = {0}; executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
+ uint32_t now = millis();
+
+ bool header_detected = false;
+ bool carrier_detected = false;
+
+// if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) { header_detected = true; carrier_detected = true; }
+ if ((stat1 & 0b100000) != 0) { header_detected = true; carrier_detected = true; }
+ else { header_detected = false; }
+
+// if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) {
+ if ((stat1 & 0b10000) != 0) {
+ carrier_detected = true;
+ if (preamble_detected_at == 0) { preamble_detected_at = now; }
+ if (now - preamble_detected_at > lora_preamble_time_ms + lora_header_time_ms) {
+ preamble_detected_at = 0;
+ if (!header_detected) { false_preamble_detected = true; }
+ //uint8_t clearbuf[2] = {0};
+ //clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X;
+ //executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
+
+ clr[7] = 0b10000;
+ cmdTransfer("->clrIrq", clr);
+ }
+ }
+
+ // TODO: Maybe there's a way of unlatching the RSSI
+ // status without re-activating receive mode?
+ // TODO - needed for LR1110? It looks like Semtech
+ // defines base RSSI as only valid for the last packet
+ // so maybe that is correct. THere is another RSSI
+ // instantaneous for when you don't want last packet.
+ //if (false_preamble_detected) { sx126x_modem.receive(); false_preamble_detected = false; }
+ return carrier_detected;
+}
+
+
+// lr1110
+uint8_t lr11xx::currentRssiRaw() {
+ // GetRssiInst
+ uint8_t cmd[7] = {2,2,0x2,0x5, 0x0,0x0};
+
+ cmdTransfer("->Modem-GetRssi", cmd, 0);
+
+#if 0 //debug rx
+ if(cmd[5] || cmd[4]) {
+ Serial.print(cmd[2]);
+ Serial.print(" ");
+ Serial.print(cmd[3]);
+ Serial.print(" ");
+ Serial.print(cmd[4]);
+ Serial.print(" ");
+ Serial.println(cmd[5]);
+ }
+#endif
+ return cmd[5];
+}
+
+// lr1110
+int ISR_VECT lr11xx::currentRssi() {
+
+ uint8_t byte;
+ byte = currentRssiRaw();
+ int rssi = -(int(byte)) / 2;
+ return rssi;
+
+#if 0
+ uint8_t byte = 0;
+ executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
+ int rssi = -(int(byte)) / 2;
+ return rssi;
+#endif
+}
+
+// unused
+uint8_t lr11xx::packetRssiRaw() {
+ uint8_t buf[3] = {0};
+ executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
+ return buf[2];
+}
+
+// used
+int ISR_VECT lr11xx::packetRssi() {
+
+ uint8_t cmd[7] = {2,4,0x2,0x4};
+
+ cmdTransfer("->Modem-GetPacketStat", cmd, 0);
+ // use RssiPkt
+ int pkt_rssi = -cmd[5] / 2;
+ Serial.print("RssiPkt ");
+ Serial.println(pkt_rssi);
+ return pkt_rssi;
+
+
+ #if 0
+ // may need more calculations here
+ uint8_t buf[3] = {0};
+ executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
+ int pkt_rssi = -buf[0] / 2;
+ return pkt_rssi;
+ #endif
+}
+
+// lr1110
+uint8_t ISR_VECT lr11xx::packetSnrRaw() {
+ uint8_t cmd[7] = {2,4,0x2,0x4};
+
+ cmdTransfer("->Modem-GetPacketStat", cmd, 0);
+ int8_t snr = (((int8_t)cmd[6]) + 2) >> 2;
+ return snr;
+}
+
+// unused
+float ISR_VECT lr11xx::packetSnr() {
+ uint8_t buf[3] = {0};
+ executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
+ return float(buf[1]) * 0.25;
+}
+
+// unused
+long lr11xx::packetFrequencyError()
+{
+ // todo: implement this, no idea how to check it on the sx1262
+ const float fError = 0.0;
+ return static_cast<long>(fError);
+}
+
+size_t lr11xx::write(uint8_t byte)
+{
+ return write(&byte, sizeof(byte));
+}
+
+// TX buffer write
+size_t lr11xx::write(const uint8_t *buffer, size_t size)
+{
+ if ((_payloadLength + size) > MAX_PKT_LENGTH) {
+ size = MAX_PKT_LENGTH - _payloadLength;
+ }
+
+
+ for (int x=0; x<size; x++) {
+ _packet[_packetIndex++] = buffer[x];
+ }
+ return size;
+}
+
+// lr1110
+int ISR_VECT lr11xx::available() {
+ uint8_t size, rxbufstart;
+
+ return available(&size, &rxbufstart);
+}
+
+// lr1110
+int ISR_VECT lr11xx::available(uint8_t *size, uint8_t *rxbufstart)
+{
+ uint8_t sz_read = 0;
+ // Rx buffer status
+ uint8_t cmd[8] = {2,3,0x2,0x3,0x0,0x0,0x0};
+
+ cmdTransfer("->rx buf stat", cmd);
+ // returns stat1, PayloadLengthRX, RxStartBufferPointer
+
+ // CMD_DAT - length is returned in Stat2
+ if ((cmd[2] & 0b110) == 0b110 ) {
+ if(size) *size = cmd[3];
+ sz_read = cmd[3];
+
+ // CMD_OK - length should be in packetlength field
+ } else if (cmd[2] & 0b100 ) {
+ if(size) *size = cmd[5];
+ sz_read = cmd[5];
+
+ }
+
+ if(rxbufstart) *rxbufstart = cmd[6];
+ #if 0
+ // rx buf size debug
+ if (rxbufstart && *rxbufstart) {
+ Serial.print("avail rxbufst>> ");
+ Serial.println(*rxbufstart);
+ }
+ #endif
+
+#if 0
+ Serial.print("rx buf ");
+ Serial.print(cmd[2]);
+ Serial.print(" ");
+ Serial.print(cmd[3]);
+ Serial.print(" ");
+ Serial.print(cmd[4]);
+ Serial.print(" rx avail sz: ");
+ Serial.print(cmd[5]);
+ Serial.print(" buf strt: ");
+ Serial.print(cmd[6]);
+ Serial.print(" rtn ");
+ Serial.println(sz_read - _packetIndexRX);
+ //Serial.print(" stat ");
+ //Serial.println(cmd[5]);
+#endif
+
+ if(sz_read)
+ return sz_read - _packetIndexRX;
+ else
+ return 0;
+
+}
+
+// lr1110
+int ISR_VECT lr11xx::read()
+{
+ uint8_t data_left, size, rxbufstart;
+
+ if(_local_rx_buffer == 0) {
+ // TODO? check this in available
+ data_left = available(&size, &rxbufstart);
+ if (!data_left) {
+ return -1;
+ }
+ }
+
+ // if received new packet
+ if (_packetIndexRX == 0) {
+ _fifo_rx_addr_ptr = rxbufstart;
+
+ readBuffer(_packetRX, size);
+ }
+
+ #if 0 // sx1262
+ // if received new packet
+ if (_packetIndex == 0) {
+ uint8_t rxbuf[2] = {0};
+ executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
+ int size = rxbuf[0];
+ _fifo_rx_addr_ptr = rxbuf[1];
+
+ readBuffer(_packet, size);
+ }
+ #endif
+
+ uint8_t byte = _packetRX[_packetIndexRX];
+ _packetIndexRX++;
+ // did we read last byte?
+ if(_packetIndexRX >= _local_rx_buffer) {
+ _local_rx_buffer = 0;
+ }
+ return byte;
+}
+
+// lr1110 - not impl - unused
+int lr11xx::peek()
+{
+ Serial.println("XXXX - lr1110 peek called - not implemented - XXXX");
+ #if 0
+ if (!available()) {
+ return -1;
+ }
+
+ // if received new packet
+ if (_packetIndexRX == 0) {
+ uint8_t rxbuf[2] = {0};
+ executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
+ int size = rxbuf[0];
+ _fifo_rx_addr_ptr = rxbuf[1];
+
+ readBuffer(_packetRX, size);
+ }
+
+ uint8_t b = _packetRX[_packetIndexRX];
+ return b;
+ #endif
+
+ return 0;
+}
+
+// lr1110 unused
+void lr11xx::flush()
+{
+}
+
+// lr1110
+void lr11xx::onReceive(void(*callback)(int))
+{
+ _onReceive = callback;
+
+ if (callback) {
+
+
+ // Clear what we enable next
+ uint8_t cmd2[9] = {6,0,0x1,0x14,0, 0, 0, 0b1100};
+
+ cmdTransfer("->clrIrq", cmd2);
+
+
+ // enable RXDone, PreambleDetected, HeaderValid(Lora),
+ // headerCRCErr 0b111 1000
+ // use SetDioIrqParams on lr1110
+ // add TXDone, timeout
+ // 0xb 1100 0000 - 0000 0100 - 1111 1100
+
+ // DIO9 enabled for RXDone, DIO11 no enables
+ // irqenable, irq enable
+
+ // Rx buffer status
+ // byte mapped wrong!
+ //uint8_t cmd[13] = {10,0,0x1,0x13,0x0,0x0,0x0,0x78, 0x0,0x0,0x0,0x0};
+ // all
+ //uint8_t cmd[13] = {10,0,0x1,0x13,0x0,0xc0,0x4,0xfc, 0x0,0x0,0x0,0x0};
+
+ // remove 0x 1100 1100 (preamble and syncword irq), upper bytes unchanged
+ //uint8_t cmd[13] = {10,0,0x1,0x13,0x0,0xc0,0x4,0xcc, 0x0,0x0,0x0,0x0};
+
+ // simple version, rxdone
+// uint8_t cmd[13] = {10,0,0x1,0x13,0x0,0x00,0x0,0x08, 0x0,0x0,0x0,0x0};
+ // simple version, rxdone, txdone
+ uint8_t cmd[13] = {10,0,0x1,0x13,0x0,0x00,0x0,0b1100, 0x0,0x0,0x0,0x0};
+
+ cmdTransfer("->dioIrqParam", cmd);
+
+ // clr irqs active when we programmed
+
+
+
+
+ #if 0
+ pinMode(_dio0, INPUT);
+
+ // set preamble and header detection irqs, plus dio0 mask
+ uint8_t buf[8];
+
+ // set irq masks, enable all
+ buf[0] = 0xFF;
+ buf[1] = 0xFF;
+
+ // set dio0 masks
+ buf[2] = 0x00;
+ buf[3] = IRQ_RX_DONE_MASK_6X;
+
+ // set dio1 masks
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+
+ // set dio2 masks
+ buf[6] = 0x00;
+ buf[7] = 0x00;
+
+ executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8);
+ #endif
+
+#ifdef SPI_HAS_NOTUSINGINTERRUPT
+ SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
+#endif
+ attachInterrupt(digitalPinToInterrupt(_dio0), lr11xx::onDio0Rise, RISING);
+ } else {
+ detachInterrupt(digitalPinToInterrupt(_dio0));
+#ifdef SPI_HAS_NOTUSINGINTERRUPT
+ SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
+#endif
+ }
+}
+
+// lr1110
+void lr11xx::receive(int size)
+{
+ loraMode();
+
+ // test
+ //modulationDirty=1;
+ setModulationParams(_sf, _bw, _cr, _ldro);
+
+
+ if (size > 0) {
+ implicitHeaderMode();
+
+ // tell radio payload length
+ _payloadLength = size;
+ packetParamsDirty=1;
+ setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+ } else {
+ explicitHeaderMode();
+ _payloadLength = size;
+ packetParamsDirty=1;
+ setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+ }
+
+ if (_rxen != -1) {
+ rxAntEnable();
+ }
+
+ // continuous mode
+ // Rx mode, no timeout (setRX)
+ // stay until command/continuous mode
+ uint8_t cmd[8] = {5,0,0x2,0x9,0xff,0xff,0xff};
+
+ cmdTransfer("->rx", cmd, 0);
+ debug_print_enabled=0;
+}
+
+// lr1110
+void lr11xx::standby()
+{
+ // TODO
+
+ // SetStandby Xosc mode
+ uint8_t cmd[6] = {3,0,0x1,0x1c,0x1};
+ // standby RC osc
+ //uint8_t cmd[6] = {3,0,0x1,0x1c,0x0};
+
+ //cmdTransfer("->stby xosc", cmd);
+ cmdTransfer("->stby RC", cmd);
+}
+
+
+// lr1110
+void lr11xx::sleep()
+{
+ // sleep mode
+ // no retention, no wakeup
+ //uint8_t cmd[10] = {7,0,0x1,0x1b,0x0, 0,0,0,0};
+ // retention, no wakeup
+ uint8_t cmd[10] = {7,0,0x1,0x1b,0x1, 0,0,0,0};
+
+ //cmdTransfer("->sleep", cmd);
+ // TODO
+}
+
+void lr11xx::enableTCXO() {
+ Serial.println("lr1110 enableTCXO() called, but internally enabled on current boards");
+ #if 0
+ #if HAS_TCXO
+ #if BOARD_MODEL == BOARD_RAK4630 || BOARD_MODEL == BOARD_HELTEC_LORA32_V3 || BOARD_MODEL == BOARD_HELTEC_CAPSULE_V3 || BOARD_HELTEC_WIRELESS_PAPER_1_1
+ uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF};
+ #elif BOARD_MODEL == BOARD_TBEAM
+ uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
+ #elif BOARD_MODEL == BOARD_RNODE_NG_22
+ uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
+ #endif
+ executeOpcode(OP_DIO3_TCXO_CTRL_6X, buf, 4);
+ #endif
+ #endif
+}
+
+// Once enabled, LR1110 needs a complete reset to disable TCXO
+void lr11xx::disableTCXO() { }
+
+// lr1110 only
+void lr11xx::setTxPower(int level, int outputPin) {
+ if (level > 22) { level = 22; }
+ else if (level < -17) { level = -17; }
+
+ _txp = level;
+
+ // PA Config
+ uint8_t PaSel, RegPASupply, PaDutyCycle, PaHPSel = 0;
+
+ // HP PA
+ if(level>15) {
+ PaSel = RegPASupply = 1;
+ if(level==22) {
+ PaDutyCycle = 4;
+ PaHPSel = 7;
+ } else if(level>=20) {
+ PaDutyCycle = 2;
+ PaHPSel = 7;
+ } else if(level>=17) {
+ // optional 1,5 instead of 4,3
+ PaDutyCycle = 4;
+ PaHPSel = 3;
+ } else if(level>=14) {
+ PaDutyCycle = 2;
+ PaHPSel = 2;
+ }
+
+ // LP PA
+ } else {
+ PaSel = RegPASupply = 0;
+ if(level==15) {
+ PaDutyCycle = 7;
+ PaHPSel = 0;
+ } else if(level>=14) {
+ PaDutyCycle = 4;
+ PaHPSel = 0;
+ } else {
+ PaDutyCycle = 0;
+ PaHPSel = 0;
+ }
+ }
+
+ uint8_t cmd3[9] = {6,0,0x02, 0x15, PaSel, RegPASupply,
+ PaDutyCycle, PaHPSel};
+
+ cmdTransfer("->pa cfg", cmd3);
+
+ uint8_t rampTime = 0x02; // 48uS
+ uint8_t cmd4[10] = {4,0,0x02, 0x11, level,rampTime};
+
+ cmdTransfer("->tx pow", cmd4);
+
+
+ // currently no low power mode for LR1110 implemented, assuming PA boost
+ // TODO
+ // RXBoosted - enabled, ~2mA more consumption in RX, better sensitivity
+ // enable
+ uint8_t cmd5[6] = {3,0,0x02, 0x27, 1};
+ // disable
+ //uint8_t cmd5[6] = {3,0,0x02, 0x27, 0};
+ cmdTransfer("->rx boost", cmd5);
+
+}
+
+uint8_t lr11xx::getTxPower() {
+ return _txp;
+}
+
+// lr1110 done
+void lr11xx::setFrequency(long freq) {
+ _frequency = freq;
+
+ Serial.print( "freq - ");
+ Serial.println(freq);
+ // set freq cmd
+ // SetRfFrequency
+ uint8_t cmd4[10] = {6,0,0x02,0x0b,
+ (freq >> 24) & 0xFF,
+ (freq >> 16) & 0xFF,
+ (freq >> 8) & 0xFF,
+ freq & 0xFF};
+
+ if( freq < 400000000 || freq > 930000000 )
+ Serial.println("freq out of range, not set");
+ else
+ cmdTransfer("->freq", cmd4);
+
+// todo - notes say fails 'with TCXO fitted' ?
+// calibrate_image(_frequency);
+
+}
+
+uint32_t lr11xx::getFrequency() {
+ // we can't read the frequency on the sx1262 / 80
+ uint32_t frequency = _frequency;
+
+ return frequency;
+}
+
+void lr11xx::setSpreadingFactor(int sf)
+{
+ if (sf < 5) {
+ sf = 5;
+ } else if (sf > 12) {
+ sf = 12;
+ }
+
+ _sf = sf;
+
+ handleLowDataRate();
+ modulationDirty=1;
+ //setModulationParams(sf, _bw, _cr, _ldro);
+}
+
+long lr11xx::getSignalBandwidth()
+{
+ int bw = _bw;
+ switch (bw) {
+ case 0x00: return 7.8E3;
+ case 0x01: return 15.6E3;
+ case 0x02: return 31.25E3;
+ case 0x03: return 62.5E3;
+ case 0x04: return 125E3;
+ case 0x05: return 250E3;
+ case 0x06: return 500E3;
+ case 0x08: return 10.4E3;
+ case 0x09: return 20.8E3;
+ case 0x0A: return 41.7E3;
+ }
+ return 0;
+}
+
+void lr11xx::handleLowDataRate(){
+ if ( long( (1<<_sf) / (getSignalBandwidth()/1000)) > 16) {
+ _ldro = 0x01;
+ } else {
+ _ldro = 0x00;
+ }
+}
+
+void lr11xx::optimizeModemSensitivity(){
+ // todo: check if there's anything we can do here
+}
+
+// lr1110
+void lr11xx::setSignalBandwidth(long sbw)
+{
+ #if 0
+ if (sbw <= 7.8E3) {
+ _bw = 0x00;
+ } else if (sbw <= 10.4E3) {
+ _bw = 0x08;
+ } else if (sbw <= 15.6E3) {
+ _bw = 0x01;
+ } else if (sbw <= 20.8E3) {
+ _bw = 0x09;
+ } else if (sbw <= 31.25E3) {
+ _bw = 0x02;
+ } else if (sbw <= 41.7E3) {
+ _bw = 0x0A;
+ } else if (sbw <= 62.5E3) {
+ _bw = 0x03;
+ } else if (sbw <= 125E3) {
+ _bw = 0x04;
+ } else if (sbw <= 250E3) {
+ _bw = 0x05;
+ } else /*if (sbw <= 250E3)*/ {
+ _bw = 0x06;
+ }
+ #endif
+
+ if (sbw <= 62.5E3) {
+ _bw = 0x03;
+ } else if (sbw <= 125E3) {
+ _bw = 0x04;
+ } else if (sbw <= 250E3) {
+ _bw = 0x05;
+ } else /*if (sbw <= 250E3)*/ {
+ _bw = 0x06;
+ }
+
+
+ handleLowDataRate();
+ modulationDirty=1;
+ //setModulationParams(_sf, _bw, _cr, _ldro);
+
+ optimizeModemSensitivity();
+}
+
+// lr1110 ok
+void lr11xx::setCodingRate4(int denominator)
+{
+ if (denominator < 5) {
+ denominator = 5;
+ } else if (denominator > 8) {
+ denominator = 8;
+ }
+
+#if 1
+ int cr = denominator - 4;
+#else
+ // lr1110 has two interleavers, test with long interleaver
+ int cr = denominator;
+#endif
+
+ _cr = cr;
+
+ modulationDirty=1;
+ //setModulationParams(_sf, _bw, cr, _ldro);
+}
+
+void lr11xx::setPreambleLength(long length)
+{
+ _preambleLength = length;
+ packetParamsDirty=1;
+ //setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
+}
+
+void lr11xx::setSyncWord(uint16_t sw)
+{
+ // lr1110 not used, so far
+ // TODO: Fix
+ // writeRegister(REG_SYNC_WORD_MSB_6X, (sw & 0xFF00) >> 8);
+ // writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF);
+ //writeRegister(REG_SYNC_WORD_MSB_6X, 0x14);
+ //writeRegister(REG_SYNC_WORD_LSB_6X, 0x24);
+}
+
+void lr11xx::enableCrc()
+{
+ _crcMode = 1;
+ packetParamsDirty=1;
+ //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+}
+
+void lr11xx::disableCrc()
+{
+ _crcMode = 0;
+ packetParamsDirty=1;
+ //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+}
+
+// done lr1110
+byte lr11xx::random()
+{
+ // generate byte of random with built in
+ // Random Number Gen (RNG)
+ NRF_RNG->EVENTS_VALRDY = 0;
+ NRF_RNG->TASKS_START = 1;
+ while (NRF_RNG->EVENTS_VALRDY == 0)
+ {
+ // wait for start
+ }
+ uint8_t rand1 = NRF_RNG->VALUE;
+ NRF_RNG->TASKS_STOP = 1;
+
+ return rand1;
+}
+
+void lr11xx::setPins(int ss, int reset, int dio0, int busy)
+{
+ _ss = ss;
+ _reset = reset;
+ _dio0 = dio0;
+ _busy = busy;
+}
+
+void lr11xx::setSPIFrequency(uint32_t frequency)
+{
+ _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
+}
+
+void lr11xx::dumpRegisters(Stream& out)
+{
+ for (int i = 0; i < 128; i++) {
+ out.print("0x");
+ out.print(i, HEX);
+ out.print(": 0x");
+ out.println(readRegister(i), HEX);
+ }
+}
+
+void lr11xx::explicitHeaderMode()
+{
+ _implicitHeaderMode = 0;
+ packetParamsDirty=1;
+ //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+}
+
+void lr11xx::implicitHeaderMode()
+{
+ _implicitHeaderMode = 1;
+ packetParamsDirty=1;
+ //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
+}
+
+void lr11xx::dioStatInternal(uint8_t *stat1, uint8_t *int2, uint8_t *int3, uint8_t *int4)
+{
+
+// NOTE - modified to use ClearIrq with all 0 clears
+// to read IRQ status, after issues with GetStatus
+
+// getStatus
+//uint8_t cmd[9] = {2,4,0x1,0x0, 0x0,0x0,0x0,0x0};
+uint8_t clr[9] = {6,0,0x1,0x14,0x0,0x0,0x0,0x0};
+int doClr = 0;
+
+//cmdTransfer("->getStatus irq", cmd);
+cmdTransfer("->ClearIrq", clr);
+
+if(stat1) *stat1 = clr[2];
+if(int2) *int2 = clr[5];
+if(int3) *int3 = clr[6];
+if(int4) *int4 = clr[7];
+}
+
+
+void lr11xx::dioStat(uint8_t *stat1, uint8_t *int2, uint8_t *int3, uint8_t *int4)
+{
+ uint8_t l_stat1, l_int2, l_int3, l_int4;
+ dioStatInternal(&l_stat1, &l_int2, &l_int3, &l_int4);
+
+ // Test for CMD_DAT, then IRQ stat was not sent
+ if((l_stat1 & 0b0110) == 6)
+ {
+ dioStatInternal(&l_stat1, &l_int2, &l_int3, &l_int4);
+ }
+
+ if(stat1) *stat1 = l_stat1;
+ if(int2) *int2 = l_int2;
+ if(int3) *int3 = l_int3;
+ if(int4) *int4 = l_int4;
+
+}
+
+uint8_t ISR_VECT lr11xx::dumpRx(void)
+{
+ uint8_t cmd2[8] = {2,3,0x2,0x3};
+
+ cmdTransfer("->getRxBuf", cmd2);
+ int packetLength = cmd2[5];
+
+ Serial.print("stat1.1 ");
+ Serial.print(cmd2[2]);
+ Serial.print(" stat2 ");
+ Serial.print(cmd2[3]);
+ Serial.print(" stat1.2 ");
+ Serial.print(cmd2[4]);
+ Serial.print(" pack len= ");
+ Serial.print(packetLength);
+ Serial.print(" start= ");
+ Serial.println(cmd2[6]);
+
+ uint8_t stat2 = cmd2[5];
+ return stat2;
+}
+
+
+void lr11xx::handleIntStatus()
+{
+ uint8_t cmd[9] = {2,4,0x1,0x0, 0x0,0x0,0x0,0x0};
+ uint8_t clr[9] = {6,0,0x1,0x14,5,11,8,0x0};
+
+ int doClr = 0;
+
+ dioStat(&cmd[2], &cmd[5], &cmd[6], &cmd[7]);
+
+ // if RXdone
+ if (cmd[7] & 0b1000) {
+ clr[7] |= 0b1000;
+ doClr = 1;
+
+ // if no CRC header error
+ if ((cmd[7] & 0b1000000) == 0) {
+
+ // critical - set foreground rx processing
+ _db_rxcnt++;
+ // received a packet
+ _packetIndexRX = 0;
+
+ } else {
+ // clear CRC header err
+ clr[7] |= 0b1000000;
+ doClr = 1;
+
+ Serial.println(" xxxxxxxx RXDone - CRC Header Err EEEEEEEEEEEEEEE");
+ }
+ }
+
+ if(cmd[7] && 0b10000 )
+ {
+ clr[7] |= 0b10000;
+ doClr = 1;
+// Serial.println("Preamble");
+ }
+ if(cmd[7] && 0b100000 )
+ {
+ clr[7] |= 0b100000;
+ doClr = 1;
+// Serial.println("Header");
+ }
+
+ // ClearIrq
+ if (doClr)
+ {
+ cmdTransfer("->clear irqs", clr, 0);
+ }
+
+}
+
+
+// lr1110 - todo 2 item - ignores error, packet length
+void ISR_VECT lr11xx::handleDio0Rise()
+{
+
+ _db_intcnt++;
+ if(_wait_tx_cmpl) {
+ TXCompl_flag=1;
+ _wait_tx_cmpl=0;
+ }
+
+// debug rx
+#if 0
+ // LoRa GetStats
+ uint8_t cmd9[15] = {2,9,0x2,0x1};
+ cmdTransfer("->getStats", cmd9);
+
+ Serial.print("Lora stats, pkts ");
+ Serial.print( (cmd9[5] << 8) | cmd[6] );
+ Serial.print(" err pkts, crc ");
+ Serial.print( (cmd9[7] << 8) | cmd[8] );
+ Serial.print(" hdr ");
+ Serial.print( (cmd9[9] << 8) | cmd[10] );
+ Serial.print(" fls sync ");
+ Serial.print( (cmd9[11] << 8) | cmd[12] );
+ Serial.print(" st ");
+ Serial.print( cmd9[2] );
+ Serial.print(" ");
+ Serial.print( cmd9[3] );
+ Serial.print(" ");
+ Serial.print( cmd9[4] );
+#endif
+
+}
+
+void ISR_VECT lr11xx::onDio0Rise()
+{
+ lr11xx_modem.handleDio0Rise();
+}
+
+
+// Debug for LR1110 State
+void lr11xx::checkOpState()
+{
+
+ if( lOpState==4 && readOpState==1 ) // RX & STD RC
+ {
+ Serial.println("rx to std");
+
+ }
+ else if( lOpState==1 && readOpState==4 )
+ {
+ Serial.println("std to rx");
+ }
+ else if( lOpState==5 && readOpState==4 )
+ {
+ Serial.println("tx to rx");
+ }
+ else if( lOpState==1 && readOpState==5 )
+ {
+ Serial.println("std to tx");
+ }
+ else if( readOpState==3 )
+ {
+ Serial.println("in fs");
+ }
+ lOpState = readOpState;
+
+}
+
+
+lr11xx lr11xx_modem;
+
+unsigned long ltime = 0;
+
+// Foreground loop for rx/tx handling
+void lr11xx::foreground(void)
+{
+ unsigned long time = millis();
+
+ // Debug state
+ //checkOpState();
+
+ if (_db_intcnt) {
+ handleIntStatus();
+ _db_intcnt = 0;
+ }
+
+ if (_db_rxcnt) {
+ _db_rxcnt=0;
+
+ //unsigned long time = millis();
+
+ uint8_t packetLength = 0;
+ available(&packetLength, NULL);
+ // receive_callback in main firmware,
+ // calls in to our read() for bytes
+ if (_onReceive && packetLength) {
+ _onReceive(packetLength);
+ }
+
+ }
+
+ // Debug, enable for continuous status prints
+ #if 0
+ if(time-ltime > 5*1000) {
+ ltime = time;
+
+ Serial.print("Tm ");
+ Serial.print(time/1000);
+ print_state();
+ // geterrors
+ uint8_t cmd3[10] = {2,3, 1,0xd};
+ cmdTransfer("errors?", cmd3, 0);
+
+ // Active Int
+ if(cmd3[2] & 0x1) {
+ dioStat(NULL, NULL, NULL, NULL);
+ }
+ }
+ #endif
+
+};
+
+void lr11xx::print_state()
+{
+ if( readOpState==1 ) {
+ Serial.println(" std");
+ }
+ else if ( readOpState==2 ) {
+ Serial.println(" std xosc");
+ }
+ else if ( readOpState==3 ) {
+ Serial.println(" FS");
+ }
+ else if ( readOpState==4 ) {
+ Serial.println(" RX");
+ }
+ else if ( readOpState==5 ) {
+ Serial.println(" TX");
+ }
+}
+
+
+#endif
\ No newline at end of file
diff --git a/lr1110.h b/lr1110.h
new file mode 100755
index 0000000..31748d7
--- /dev/null
+++ b/lr1110.h
@@ -0,0 +1,176 @@
+// Copyright (c) Sandeep Mistry. All rights reserved.
+// Licensed under the MIT license.
+
+// Modifications and additions copyright 2023 by Mark Qvist
+// Obviously still under the MIT license.
+
+// LR1110 Modifications and additions copyright 2024 by Kevin Brosius
+// MIT license.
+
+#ifndef LR1110_H
+#define LR1110_H
+
+#include <Arduino.h>
+#include <SPI.h>
+#include "Modem.h"
+
+#define LORA_DEFAULT_SS_PIN 10
+#define LORA_DEFAULT_RESET_PIN 9
+#define LORA_DEFAULT_DIO0_PIN 2
+#define LORA_DEFAULT_RXEN_PIN -1
+#define LORA_DEFAULT_TXEN_PIN -1
+#define LORA_DEFAULT_BUSY_PIN -1
+
+#define PA_OUTPUT_RFO_PIN 0
+#define PA_OUTPUT_PA_BOOST_PIN 1
+
+#define RSSI_OFFSET 157
+
+class lr11xx : public Stream {
+public:
+ lr11xx();
+
+ int begin(long frequency);
+ void end();
+
+ int beginPacket(int implicitHeader = false);
+ int endPacket();
+
+ int parsePacket(int size = 0);
+ int packetRssi();
+ int currentRssi();
+ bool dcd();
+ uint8_t packetRssiRaw();
+ uint8_t currentRssiRaw();
+ uint8_t packetSnrRaw();
+ float packetSnr();
+ long packetFrequencyError();
+
+ // from Print
+ virtual size_t write(uint8_t byte);
+ virtual size_t write(const uint8_t *buffer, size_t size);
+
+ // from Stream
+ virtual int available();
+ virtual int available(uint8_t *size, uint8_t *rxbufstart);
+ virtual int read();
+ virtual int peek();
+ virtual void flush();
+
+ void onReceive(void(*callback)(int));
+
+ void receive(int size = 0);
+ void standby();
+ void sleep();
+
+ bool preInit();
+ uint8_t getTxPower();
+ void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
+ uint32_t getFrequency();
+ void setFrequency(long frequency);
+ void setSpreadingFactor(int sf);
+ long getSignalBandwidth();
+ void setSignalBandwidth(long sbw);
+ void setCodingRate4(int denominator);
+ void setPreambleLength(long length);
+ void setSyncWord(uint16_t sw);
+ uint8_t modemStatus();
+ void enableCrc();
+ void disableCrc();
+ void enableTCXO();
+ void disableTCXO();
+
+ void rxAntEnable();
+ void loraMode();
+ void waitOnBusy(uint8_t doYield = 1);
+ void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
+ void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
+ void writeBuffer(const uint8_t* buffer, size_t size);
+ void readBuffer(uint8_t* buffer, size_t size);
+ void setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc);
+
+ void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
+
+ // deprecated
+ void crc() { enableCrc(); }
+ void noCrc() { disableCrc(); }
+
+ byte random();
+
+ void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN /*, int rxen = LORA_DEFAULT_RXEN_PIN */);
+ void setSPIFrequency(uint32_t frequency);
+
+ void dumpRegisters(Stream& out);
+
+ void foreground(void);
+
+private:
+ void explicitHeaderMode();
+ void implicitHeaderMode();
+
+ void handleDio0Rise();
+
+ uint8_t readRegister(uint16_t address);
+ void writeRegister(uint16_t address, uint8_t value);
+ uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
+uint16_t cmdTransfer(const char *prt, uint8_t *cmd);
+uint16_t cmdTransfer(const char *prt, uint8_t *cmd, bool );
+uint16_t A32Transfer(uint16_t opcode, uint16_t address, uint16_t value);
+void getErrors(void);
+int decode_stat(uint8_t stat);
+int decode_stat(const char *prt,uint8_t stat1,uint8_t stat2,uint8_t print_it);
+int decode_stat(uint8_t stat, uint8_t stat2);
+void getErrors2(void);
+void doSetup(void);
+//void dioStat(void);
+void dioStatInternal(uint8_t *stat1, uint8_t *int2, uint8_t *int3, uint8_t *int4);
+void dioStat(uint8_t *stat1, uint8_t *int2, uint8_t *int3, uint8_t *int4);
+uint8_t dumpRx(void);
+void handleIntStatus(void);
+void checkOpState(void);
+void checkTXstat(void);
+void print_state(void);
+
+
+ static void onDio0Rise();
+
+ void handleLowDataRate();
+ void optimizeModemSensitivity();
+
+ void reset(void);
+ void calibrate(uint8_t);
+ void calibrate_image(long frequency);
+
+private:
+ SPISettings _spiSettings;
+ int _ss;
+ int _reset;
+ int _dio0;
+ int _rxen;
+ int _busy;
+ long _frequency;
+ int _txp;
+ uint8_t _sf;
+ uint8_t _bw;
+ uint8_t _cr;
+ uint8_t _ldro;
+ int _packetIndex;
+ int _packetIndexRX;
+ int _local_rx_buffer;
+ int _preambleLength;
+ int _implicitHeaderMode;
+ int _payloadLength;
+ int _crcMode;
+ int _fifo_tx_addr_ptr;
+ int _fifo_rx_addr_ptr;
+ uint8_t _packet[255];
+ uint8_t _packetRX[255];
+ bool _preinit_done;
+ void (*_onReceive)(int);
+ int modulationDirty;
+ int packetParamsDirty;
+};
+
+extern lr11xx lr11xx_modem;
+
+#endif
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────